package cloud.health.common.file.infrastructure;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.net.SocketAddress;
import java.util.Objects;
import java.util.Optional;

@Slf4j
public abstract class AbstractNettyClient {

    private Bootstrap bootstrap;
    private NioEventLoopGroup eventExecutors;

    /**
     * 获取管道配置
     *
     * @return 管道配置
     */
    protected abstract ChannelInitializer<SocketChannel> channelInitializer();

    /**
     * 初始化
     */
    protected void init() {
        this.eventExecutors = new NioEventLoopGroup();
        // 创建bootstrap对象，配置参数
        this.bootstrap = new Bootstrap();
        // 设置线程组
        bootstrap.group(eventExecutors)
                // 设置客户端的通道实现类型
                .channel(NioSocketChannel.class)
                // keepalive
                .option(ChannelOption.SO_KEEPALIVE, true)
                // 使用匿名内部类初始化通道
                .handler(this.channelInitializer());
    }

    /**
     * 连接
     *
     * @param hostname 主机名
     * @param port     端口号
     */
    protected ChannelFuture connect(String hostname, int port) {
        try {
            long t = System.currentTimeMillis();
            ChannelFuture future = this.bootstrap.connect(hostname, port).sync();
            if (Objects.isNull(future)) {
                return null;
            }
            log.info("创建管道耗时  = {}ms", System.currentTimeMillis() - t);
            if (future.isSuccess() && future.channel().isActive()) {
                return future;
            }
        } catch (Exception e) {
            log.info("创建通信管道失败 -->", e);
        }
        return null;
    }

    /**
     * 连接
     *
     * @param hostname 主机名
     * @param port     端口
     * @param ctx      管道
     * @return 管道
     */
    protected ChannelFuture connect(String hostname, int port, ChannelHandlerContext ctx) {
        if (!Optional.ofNullable(ctx).isPresent()) {
            return null;
        }
        try {
            ChannelFuture future = this.bootstrap.connect(hostname, port).sync();
            if (Objects.isNull(future)) {
                return null;
            }
            if (future.isSuccess() && future.channel().isActive()) {
                return future;
            }
        } catch (Exception e) {
            log.info("创建通信管道失败 -->", e);
        }
        return null;
    }

    /**
     * 连接
     *
     * @param remoteAddress 远程地址
     * @param localAddress  本地地址
     * @return 管道
     */
    protected ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
        try {
            ChannelFuture future = this.bootstrap.connect(remoteAddress, localAddress).sync();
            if (future.isSuccess() && future.channel().isActive()) {
                return future;
            }
        } catch (Exception e) {
            log.info("创建通信管道失败 -->", e);
        }
        return null;
    }

    /**
     * 释放
     */
    @Override
    public void finalize() throws Throwable {
        if (Objects.nonNull(this.eventExecutors)) {
            this.eventExecutors.shutdownGracefully();
        }
        super.finalize();
    }

}
